import 'dart:async';
import 'dart:convert';
import 'transformer.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

typedef void _Listen<T>(T state);
typedef void _Callback<T>(T state);
typedef List<dynamic> _Memo<T>(T state);
typedef Widget _Builder<T>(BuildContext context, T state);
typedef Future<bool> _Cache<T>(T state);
typedef dynamic _Decoder<T>(dynamic json);
typedef String? _PreContent(String? content);

/// 请叫我code哥
/// ```dart
/// //不支持缓存方式
/// class NoCacheCounterState {
///   int counter = 0;
/// }
/// //使用
/// var observableCounter = Observable(NoCacheCounterState());
///
/// //支持缓存方式
/// class CacheCounterState {
///   int counter;
///
///   CacheCounterState({this.counter = 0});
///
///   static CacheCounterState fromJson(dynamic json) {
///     return CacheCounterState(
///       counter: json["counter"],
///     );
///   }
///
///   Map<String, dynamic> toJson() {
///     final Map<String, dynamic> data = Map<String, dynamic>();
///     data['counter'] = this.counter;
///     return data;
///   }
/// }
///
/// //使用
/// var observableCounter = Observable(CacheCounterState(),
///     cacheKey: 'CounterState_CacheKey', decoder: CacheCounterState.fromJson);
/// ```
class Observable<T> {
  T state;
  late StreamController<T> _controller;
  late Stream<T> _stream;
  late _Listen<T>? _listen;
  late bool _change;
  late _Cache? _cache;
  late _Decoder? _decoder;
  late _PreContent? _preWrite;
  late _PreContent? _preRead;

  /// * 设置cacheKey 即为生效，状态变化即会缓存，数据对象需要实现fromJson和toJson
  /// * 如果存在缓存，使用缓存赋值state
  /// * 写入前处理数据回调，读取前处理数据回调，一般用于加解密
  /// * cacheKey is set to take effect, state changes are cached,
  ///   and data objects need to implement fromJson and toJson
  /// * if a cache exists, use the cache assignment state
  /// * write pre-processing data callback, read pre-processing data callback,
  ///   generally used for encryption and decryption
  Observable(this.state,
      {String? cacheKey,
      _Decoder? decoder,
      _PreContent? preWrite,
      _PreContent? preRead}) {
    _preWrite = preWrite;
    _preRead = preRead;
    _decoder = decoder;
    _initCache(cacheKey);
    _init(cacheKey);
  }

  void _init(String? cacheKey) {
    if (cacheKey != null && cacheKey.length > 0) {
      _cache = _setCache(cacheKey);
    } else {
      _cache = null;
    }
    _controller = StreamController.broadcast();
    _stream = _controller.stream;
    _listen = null;
    _change = true;
  }

  Widget _builder(_Builder<T> builder, {_Memo<T>? memo}) {
    return _ObservableWidget<T>(
        state, _stream, builder, memo, _listen, _change, _cache);
  }

  /// * 通知状态改变，触发builder
  /// * Notifies a state change, triggering the Builder
  void notify(_Callback<T> callback) async {
    callback(state);
    if (!_controller.isClosed) _controller.add(state);
  }

  /// * 监听变化 change = false, 不变化也会监听notify，不会触发builder
  /// * Listen for change = false, it listens for notify without changing,
  ///   builder will not be triggered
  void listen(_Listen<T>? listen, {bool change = true}) {
    _change = change;
    _listen = listen;
  }

  /// * 序列化存储
  /// * serialized storage
  _Cache<T>? _setCache<T>(String cacheKey) {
    final func = (T state) async {
      try {
        final prefs = await SharedPreferences.getInstance();
        String? content = jsonEncode(state);
        if (_preWrite != null) {
          content = _preWrite!(content) ?? '';
        }
        final result = await prefs.setString(cacheKey, content);
        return result;
      } catch (e) {
        debugPrint('setCache key:$cacheKey fail, error:${e.toString()}');
      }
      return false;
    };
    return func;
  }

  /// * 读取缓存数据
  /// * read cached data
  Future<T?> _getCache(String cacheKey) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      String? jsonStr = prefs.getString(cacheKey);
      if (_preRead != null) {
        jsonStr = _preRead!(jsonStr);
      }
      if (_decoder != null && jsonStr != null && jsonStr.length > 0) {
        final map = await Transformer.transformer(jsonStr);
        T state = _decoder!(map);
        return state;
      }
    } catch (e) {
      debugPrint('getCache key:$cacheKey fail, error:${e.toString()}');
    }
    return null;
  }

  /// * 初始化state数据
  /// * initialize the state data
  void _initCache(String? cacheKey) async {
    if (cacheKey != null && cacheKey.length > 0) {
      T? stateCache = await _getCache(cacheKey);
      if (stateCache != null) {
        state = stateCache;
        notify((st) {});
      }
    }
  }
}

class _ObservableWidget<T> extends StatefulWidget {
  final T state;
  final Stream<T> stream;
  final _Listen<T>? listen;
  final _Memo<T>? memo;
  final _Builder<T> builder;
  final _Cache? cache;
  final bool change;

  _ObservableWidget(this.state, this.stream, this.builder, this.memo,
      this.listen, this.change, this.cache,
      {Key? key})
      : super(key: key);

  @override
  _ObservableWidgetState createState() => _ObservableWidgetState<T>(
      state, stream, memo, builder, listen, change, cache);
}

class _ObservableWidgetState<T> extends State<_ObservableWidget<T>> {
  late StreamSubscription<T> _subscription;
  late List<dynamic>? _lastMemo;

  T _state;
  final Stream<T> _stream;
  final _Listen<T>? _listen;
  final _Memo<T>? _memo;
  final _Builder<T> _builder;
  final _Cache? _cache;
  final bool _change;

  _ObservableWidgetState(this._state, this._stream, this._memo, this._builder,
      this._listen, this._change, this._cache);

  @override
  void initState() {
    if (_memo != null) {
      _lastMemo = [..._memo!(_state)];
    }

    _subscription = _stream.listen((state) async {
      _state = state;
      if (_listen != null && !_change) _listen!(state);
      List<dynamic>? nowMemo;
      if (_memo != null) {
        nowMemo = [..._memo!(state)];
      }
      if (_lastMemo != null && _lastMemo!.isNotEmpty ||
          nowMemo != null && nowMemo.isNotEmpty) {
        for (var i = 0; i < _lastMemo!.length; i++) {
          if (_lastMemo![i] != nowMemo![i] && mounted) {
            if (_listen != null && _change) _listen!(state);
            _lastMemo = nowMemo;
            if (_cache != null) {
              await _cache!(state);
            }
            (context as Element).markNeedsBuild();
            break;
          }
        }
      }
    });
    super.initState();
  }

  @override
  void dispose() {
    _subscription.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return _builder(context, _state);
  }
}

/// 请叫我code哥
/// ```dart
/// //*****************************************************
/// // use the example:
/// // 使用示例
/// //*****************************************************
/// class CounterState {
///   int counter = 0;
/// }
///
/// var observableCounter = Observable(CounterState());
///
/// class TestWidget extends StatefulWidget {
///   @override
///   _TestWidgetState createState() => _TestWidgetState();
/// }
///
/// class _TestWidgetState extends State<TestWidget> {
///   @override
///   void initState() {
///     observableCounter.listen((state) {
///       print(state.counter);
///     });
///     super.initState();
///   }
///
///   @override
///   Widget build(BuildContext context) {
///     return Column(
///       children: [
///         ObservableBuilder<CounterState>(
///           create: observableCounter,
///           memo: (state) => [state.counter],
///           builder: (context, state) {
///             return Text('${state.counter}');
///           },
///         ),
///         IconButton(
///           onPressed: () => observableCounter.notify((state) => state.counter++),
///           icon: Icon(Icons.add),
///         )
///       ],
///     );
///   }
/// }
/// //*****************************************************
/// // provide a solution to change the theme
/// // 提供一种改变主题的解决方案
/// // change the theme example:
/// // 使用示例
/// //*****************************************************
/// enum ThemeType {
///   dark,
///   light,
/// }
///
/// class ThemeState {
///   ThemeType type = ThemeType.dark;
///
///   Color get title =>
///       {ThemeType.dark: Colors.white, ThemeType.light: Color(0xff3c3f41)}[type]!;
///
///   Color get body =>
///       {ThemeType.dark: Color(0xff3c3f41), ThemeType.light: Colors.white}[type]!;
/// }
///
/// var observableTheme = Observable(ThemeState());
/// // change the theme：
/// observableTheme.notify((theme) => theme.type =
///     theme.type == ThemeType.light
///         ? ThemeType.dark
///         : ThemeType.light);
///
/// class ThemeBuilder extends StatelessWidget {
///   const ThemeBuilder({
///     Key? key,
///     required this.builder,
///   }) : super(key: key);
///
///   final Widget Function(BuildContext, ThemeState) builder;
///
///   @override
///   Widget build(BuildContext context) => ObservableBuilder<ThemeState>(
///       create: observableTheme, memo: (theme) => [theme.type], builder: builder);
/// }
/// ```
class ObservableBuilder<T> extends StatelessWidget {
  /// 默认builder函数不会跟随父组件rebuild，只会监听数据变化触发rebuild。
  /// 当builder函数使用了其它状态otherState(非回调参数state)，通过给ObservableBuilder设置ValueKey(otherState)，使其触发rebuild。
  /// StatelessWidget引用其它状态otherState需要设置key，使其触发rebuild。
  /// StatefulWidget通过参数传递其它状态otherState不需要设置key，参数变化会触发rebuild。
  const ObservableBuilder({
    Key? key,
    required this.create,
    this.memo,
    required this.builder,
  }) : super(key: key);

  final Observable<T> create;
  final _Memo<T>? memo;
  final _Builder<T> builder;

  @override
  Widget build(BuildContext context) => create._builder(builder, memo: memo);
}

extension ObservableEx on dynamic {
  /// * 针对基本数据类型提供便捷初始化
  /// * provides easy initialization for basic data types
  Observable<BasicClass> get obs => Observable(BasicClass(this));
}

/// * 支持基本类型 1.obs/'1'.obs/List().obs/Map().obs ... 方式
/// * supports the basic type 1.obs/'1'.obs/List().obs/Map().obs... way
class BasicClass {
  dynamic current;

  BasicClass(this.current);
}
